package com.freeheart.validation.constraintvalidators.recent;


import com.freeheart.validation.constraints.Recent;
import lombok.Data;
import org.springframework.util.StringUtils;

import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 收集{@code com.freeheart.validation.constraints.Recent}注解的所有属性
 * <p>
 * 经验：当注解属性过多时，使用类来进行封装，目的是重用时将会很方便
 *
 * @author: EmperorHeart
 * @date: 2025/5/10 1:38
 * @description
 */
@Data
public class RecentProperties {
    /**
     * 最近多少时间单位
     */
    private long value;
    /**
     * 校验失败后的描述信息
     */
    private String msg;
    /**
     * 时间单位
     */
    private TimeUnit timeUnit;
    /**
     * 计算时差时，是否进行截断。
     */
    private boolean truncate;
    /**
     * 校验时间区间是否包括未来
     */
    private boolean containFuture;
    /**
     * 字符串的时间格式
     */
    private String format;
    /**
     * 对日期字符串的格式生成的DateTimeFormatter
     */
    private DateTimeFormatter dateTimeFormatter;
    /**
     * TimeUnit与ChronoUnit单位转化Map
     */
    private static final Map<TimeUnit, ChronoUnit> timeUnitMap = new HashMap<>(8);
    /**
     * 翻译TimeUnit的Map(字典)
     */
    private static final Map<TimeUnit, String> timeUnitDescMap = new HashMap<>(8);

    static {
        timeUnitMap.put(TimeUnit.DAYS, ChronoUnit.DAYS);
        timeUnitMap.put(TimeUnit.HOURS, ChronoUnit.HOURS);
        timeUnitMap.put(TimeUnit.MINUTES, ChronoUnit.MINUTES);
        timeUnitMap.put(TimeUnit.SECONDS, ChronoUnit.SECONDS);
        timeUnitMap.put(TimeUnit.MILLISECONDS, ChronoUnit.MILLIS);
        timeUnitMap.put(TimeUnit.MICROSECONDS, ChronoUnit.MICROS);
        timeUnitMap.put(TimeUnit.NANOSECONDS, ChronoUnit.NANOS);

        timeUnitDescMap.put(TimeUnit.DAYS, "天");
        timeUnitDescMap.put(TimeUnit.HOURS, "小时");
        timeUnitDescMap.put(TimeUnit.MINUTES, "分钟");
        timeUnitDescMap.put(TimeUnit.SECONDS, "秒");
        timeUnitDescMap.put(TimeUnit.MILLISECONDS, "毫秒");
        timeUnitDescMap.put(TimeUnit.MICROSECONDS, "微秒");
        timeUnitDescMap.put(TimeUnit.NANOSECONDS, "纳秒");
    }

    public RecentProperties(Recent constraintAnnotation) {
        this.value = constraintAnnotation.value();
        this.timeUnit = constraintAnnotation.timeUnit();
        this.truncate = constraintAnnotation.truncate();
        this.containFuture = constraintAnnotation.containFuture();
        this.format = constraintAnnotation.formater();
        this.dateTimeFormatter = DateTimeFormatter.ofPattern(this.format);
        this.msg = handlerErrorMsg(constraintAnnotation.message());
    }

    /**
     * 是否不需要校验
     * true：不校验，放行
     * false：进行校验
     *
     * @param object 校验值
     * @return 是否不校验
     */
    public boolean notValid(Object object) {
        // 1.null值不做校验，请使用@NotNull进行控制
        boolean condition1 = object == null;
        // 2.对于String类型的时间格式，控制不做校验，请使用@NotEmpty控制
        boolean condition2 = object instanceof String && !StringUtils.hasText((String) object);
        // 3.小于1，会失去意义
        boolean condition3 = this.getValue() < 1;
        return condition1 || condition2 || condition3;
    }

    /**
     * 根据时间差距，判断当前条件是否检验通过
     *
     * @param gap 时间差
     * @return true|false
     */
    public boolean pass(long gap) {
        return gap >= 0 && gap < this.value;
    }

    /**
     * 获取当前的ChronoUnit单位
     *
     * @return ChronoUnit
     */
    public ChronoUnit currentUnit() {
        return timeUnitMap.get(timeUnit);
    }

    /**
     * 对校验失败描述模板进行数据填充
     *
     * @param message 失败信息模板
     * @return 校验失败描述信息
     */
    private String handlerErrorMsg(String message) {
        if (message == null) {
            return String.format("不在最近%s %s内", value, timeUnitDescMap.get(timeUnit));
        }
        return message.replaceAll("\\{value}", value + "")
                .replaceAll("\\{timeUnit}", timeUnitDescMap.get(timeUnit));
    }

}
